package sg.edu.nus.iss.billing.dao;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author  Koo Eng Khoon
			Saravana Kumar
			Yeo Hee Ling
			Ananda Purna Pryana
			Bee Hong
			Thureim
			Yin Ni Tun
			Zhou Zifeng
 *
 */
public class BaseDAO <T extends Serializable> {

	private String dataDirection;
	private Class<T> clazz;
	private String dataName;
	
	public BaseDAO(String dataDirection, String dataName, Class<T> clazz) {
		super();
		this.dataDirection = dataDirection;
		this.dataName = dataName;
		this.clazz = clazz;
	}

	@SuppressWarnings("unchecked")
	public List<T> getElementListByAttribute(String attr, java.io.Serializable id){
		try{
	    	ObjectInputStream in = new ObjectInputStream (new FileInputStream(dataDirection + dataName));
			List<T> list = (List<T>) in.readObject();
			return getElementList(list, attr, id);
		} catch (IOException e) {
			//do nothing, it is normal not to be able to find the file
		} catch(Exception e){
	        e.printStackTrace();
	    }
	    return new ArrayList<T>();
	}
	
	@SuppressWarnings("unchecked")
	public T saveElementByPK(T obj, String pkAttrName, java.io.Serializable id ){
		try{
			if(obj == null)
				return null;
			ObjectInputStream in;
			List<T> list;
			try {
				in = new ObjectInputStream (new FileInputStream(dataDirection + dataName));
				list = (List<T>) in.readObject();
			} catch (IOException e) {
				list = new ArrayList<T>();
			}
			
			List<T> result = getElementList(list, pkAttrName, id);
			list.removeAll(result);
			list.add(obj);
			
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(dataDirection + dataName));
			out.writeObject(list);
			out.close();
			
	    	return obj;
	    } catch(Exception e){
	        e.printStackTrace();
	    }
	    return null;
	}
	
	@SuppressWarnings("unchecked")
	public List<T> getElementList(){
		try{
	    	ObjectInputStream in = new ObjectInputStream (new FileInputStream(dataDirection + dataName));
			List<T> list = (List<T>) in.readObject();
			return list;
		} catch (IOException e) {
			//do nothing, it is normal not to be able to find the file
		} catch(Exception e){
	        e.printStackTrace();
	    }
	    return new ArrayList<T>();
	}
	
	@SuppressWarnings("unchecked")
	public List<T> deleteElementByPK(String pkAttrName, java.io.Serializable id ){
		try{
			ObjectInputStream in;
			List<T> list;
			try {
				in = new ObjectInputStream (new FileInputStream(dataDirection + dataName));
				list = (List<T>) in.readObject();
			} catch (IOException e) {
				list = new ArrayList<T>();
			}
			
			List<T> result = getElementList(list, pkAttrName, id);
			list.removeAll(result);
			
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(dataDirection + dataName));
			out.writeObject(list);
			out.close();
			
	    	return result;
	     }catch(Exception e){
	        e.printStackTrace();
	     }
		return null;
	   }
	
	private List<T> getElementList(List<T> list, String attr, java.io.Serializable id) throws Exception
	{
		List<T> resultList = new ArrayList<T>();
		String strMethodName = "get" + (char) (attr.charAt(0) - 32) + attr.substring(1);
		Method method = getMethod(strMethodName, null);;
		for(T t: list)
		{
			Object obj = method.invoke(t);
			if(id.toString().equals(obj.toString()))
				resultList.add(t);
		}
		return resultList;
	}
	
	private Method getMethod(String strMethodName, Class<T>[] clsArg) {
		Class<T> me = clazz;
		Class<? super T> su = me.getSuperclass();
		Method method = null;
		try {
			method = me.getDeclaredMethod(strMethodName, clsArg);
		} catch (Exception ex) {
		}
		if (method != null) {
			return method;
		}
		do {
			try {
				method = su.getDeclaredMethod(strMethodName, clsArg);
			} catch (Exception ex) {
			}
			if (method != null) {
				return method;
			}
		} while (!(su = su.getSuperclass()).getName().equals("java.lang.Object"));
		return method;
	}

}
